package ocp.context;

//import edu.stanford.smi.protegex.owl.swrl.bridge.exceptions.DatatypeConversionException;
import java.util.*;
import java.io.*;
import java.text.SimpleDateFormat;

/**
 * The root for all contextual objects. The class Context defines the structure 
 * every context should fulfill. Altough every context is different, they all
 * share a common structure. They are compossed of bits of descriptive 
 * information with a concrete meaning. Every context is then defined by
 * a bunch of ContextInformation instances.
 * All subclasses of Context should call to the constructor of context
 * in order to initialice the contextual information structures.
 * @see ContextualInformation
 * @see ContextualInformationList
 * @author Ignacio Nieto Carvajal.
 */
public abstract class Context extends Observable implements java.io.Serializable
{
	
       // private static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        
        /** Name of the context */
        protected String name = "nameless";
        
        /** Unique id of this context */
        protected String id = "";
        
        /** Unique id of this context */
        //protected Long time;
        protected Long dateTime;
        
        
        /** component address of the source of the event */
        protected ComponentAddress sourceInformation; 
        
        /** component address of the notifier of the event (may be different 
         * from the source of the event) */
        protected ComponentAddress notifierInformation;
        
	public Context(String name, String id) {
            this.name = name;
            this.id = id;
            this.dateTime = new Long(System.currentTimeMillis());
	}

	public Context(String name, String id, ComponentAddress source, ComponentAddress notifier) {
            this.name = name;
            this.id = id;
            this.sourceInformation = source;
            this.notifierInformation = notifier;
            this.dateTime = new Long(System.currentTimeMillis());
	}
        
        public String getTime() {
            String s = null;
            Calendar c = Calendar.getInstance();
            c.setTimeInMillis(dateTime.longValue());
            s = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")).format(c.getTime());
            return s;
        }
        
        public void updateTime(){
            this.dateTime = new Long(System.currentTimeMillis());
        }

        // SOS TODO
        public void updateDateTime(String s){
            //this.dateTime = dateTime;
            this.dateTime = new Long(System.currentTimeMillis());
        }

    /* CARDEA */    
	public String getType()                         { 
        int c = id.indexOf("-");
        if( c==-1 ) return "";
        else return id.substring(0 , c);
    }
    
	public String getName()                         { return name; }
        public String getId()                           { return id; }
        public ComponentAddress getSourceInformation()  { return sourceInformation; }
        public ComponentAddress getNotifierInformation(){ return notifierInformation; }
        
        
        public void setName(String newName)             { name = newName; }
        public void setId(String newId)                 { id = newId; }
        public void setSourceInformation(ComponentAddress si) { 
            sourceInformation = si;
            this.updateTime();
        }
        public void setNotifierInformation(ComponentAddress ni) {
            notifierInformation = ni;
            this.updateTime();
        }

	/** inform all observers of the context that the context changed. */
	public void contextChanged()
	{
		setChanged();
		notifyObservers();
	}

	/** inform all observers of the context that the context changed, 
	 * giving some information about the change. */
	public void contextChanged(Object arg)
	{
		setChanged();
		notifyObservers(arg);
	}
	
	/** returns a string representation of the context, in XML format. */
	public String toString()	{ return this.toXML(); }

        /** returns true if the given object is equal to this context, false otherwise */
        // TODO!!!!
        public boolean equals(Object o) {
            if (o instanceof Context)
                return (((Context) o).getId().equals(id));
            else return false;
        }
        
	/** updates the contextual information, asking its adapter(s) */
	public abstract void updateContextualInformation() 
		throws ContextualInformationAbsentException;
	
	/** returns the contextual information associated to this context */
	public abstract ContextualInformationList getContextualInformation()
		throws ContextualInformationAbsentException;

	/** 
	 * Stores the contextual information as an XML file.
	 * @param xmlFile thename of the file to generate
	 * @return true if context could be successfuly saved, false otherwise.
	 */
	public boolean storeAsXML(String xmlFile)
	{

		String xml = this.toXML();

		// sanity check of the xml string.
		if (xml == null) return false;
		if (!xml.startsWith("<?xml")) xml = "<?xml version=\"1.0\"?>\n" + xml;
		try
		{
			PrintWriter pw = new PrintWriter(new BufferedWriter(
					new FileWriter(xmlFile)));
			pw.println(xml);
			pw.close();
			return true;
		} catch (IOException ioe) { return false; }
	}

	/** Returns a String containing an XML version of the context */
	public abstract String toXML();

	/** loads the contextual information of this context from a XML file 
	 * @param xmlFile file from wich to load the contextual information.
	 * @return true if the context was loaded successfully from the xml file, 
	 * false otherwise.
	 */
	public abstract boolean loadFromXML(String xmlFile);
        
        /**
         * returns a string containing the hierarchy of contexts and contextual
         * information this context carries.
         */
        public abstract String extractHierarchyAsString();
        
        public long getDateTime(){
            return dateTime.longValue();
        }
}


